const path = require("path");//nodejs核心模块，专门用来处理路径问题
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

// nodejs核心模块，直接使用
const os = require("os")
// cpu核数
const threads = os.cpus().length;

function getStyleLoaders(pre) {
  return [
    MiniCssExtractPlugin.loader,
    // 执行顺序，从右到左(从下到上)
    'css-loader', //将css资源编译成commonjs的模块到js中
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: [
            [
              'postcss-preset-env',
            ],
          ],
        },
      },
    },
    pre
  ].filter(Boolean) //array.filter(Boolean)：过滤假数据（false,0,-0."",null,undefined,NaN）
}


module.exports = {
  // 入口
  entry: "./src/main.js",
  // 输出
  output: {
    // 文件的输出路径
    path: path.resolve(__dirname, "../dist"),
    // 文件名
    filename: "static/js/[name].js",
    // 动态导入输出资源命名方式
    chunkFilename:"static/js/[name].chunk.js",//chunk区分于主文件
    // 图片、字体等资源命名方式
    assetModuleFilename: 'static/media/[hash:10][ext]',
    // 自动清空上次打包的内容
    clean: true,
  },
  // 加载器
  module: {
    rules: [
      {
        // 匹配到一个loader后，不会再向下匹配
        // 减少编译时间
        oneOf: [
          // loader的配置
          {
            test: /\.css$/, //只检测.css文件
            use: getStyleLoaders(),
          },
          {
            test: /\.less$/, //只检测.less文件
            use: getStyleLoaders("less-loader"),
          },
          {
            test: /\.s[ac]ss$/, //只检测.less文件
            use: getStyleLoaders("sass-loader"),
          },
          // 将小于6kb的图片转为data URL(base64编码)，大于的不转，减少连接
          // 默认8kb，通过parser.dataUrlCondition.maxSize自定义
          {
            test: /\.(png|jpe?g|gif|webp|svg)$/,
            type: 'asset',
            parser: {
              // 将小于4kb的文件转化为base64的url
              dataUrlCondition: {
                maxSize: 6 * 1024 // 6kb
              }
            },
            // generator: {
            //   // :10 hash值保留10位
            //   filename: 'static/images/[hash:10][ext][query]'
            // }
          },
          {
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
            type: 'asset/resource',
          //   generator: {
          //     // :10 hash值保留10位
          //     filename: 'static/media/[hash:10][ext][query]'
          //   }
          },
          {
            test: /\.js$/,
            // exclude: /node_modules/, //排除node_modules,不进行转化
            include: path.resolve(__dirname, 'src'),
            use: [
              {
                loader: "thread-loader",//开启多进程
                options: {
                  workers: threads //数量
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  cacheDirectory: true, // 开启babel编译缓存
                  cacheCompression: false, // 缓存文件不要压缩
                  plugins: ['@babel/plugin-transform-runtime'] //// 减少代码体积
                }
              }
            ]
          }
        ]
      }
    ],
  },
  // 插件
  plugins: [
    // eslint插件配置，plugin使用new
    // new ESLintPlugin({
    //   // eslint检测文件的位置
    //   context: path.resolve(__dirname, '../src'),
    //   exclude: "node_modules", // 默认值
    //   cache: true,//开启缓存
    //   // 缓存目录
    //   cacheLocation: path.resolve(
    //     __dirname,
    //     "../node_modules/.cache/.eslintcache"
    //   ),
    //   threads, // 开启多进程
    // }),
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点：1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    // 提取css成单独文件
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/[name].css",
      chunkFilename:"static/css/[name].chunk.css"
    }),
    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminGenerate,
        options: {
          plugins: [
            ["gifsicle", { interlaced: true }],
            ["jpegtran", { progressive: true }],
            ["optipng", { optimizationLevel: 5 }],
            [
              "svgo",
              {
                plugins: [
                  "preset-default",
                  "prefixIds",
                  {
                    name: "sortAttrs",
                    params: {
                      xmlnsOrder: "alphabetical",
                    },
                  },
                ],
              },
            ],
          ],
        },
      },
    }),
  ], 
  // 压缩的放这里
  optimization: {
    minimize: true,
    minimizer: [
      new CssMinimizerPlugin(), //压缩css
      // 当生产模式会默认开启TerserPlugin，但是我们需要进行其他配置，就要重新写了
      new TerserPlugin({ //压缩js
        parallel: threads, // 开启多进程
      }),
    ],
    // 代码分割配置
    splitChunks: {
      chunks: "all", // 对所有模块都进行分割
      // 以下是默认值
      // minSize: 20000, // 最小文件大小，低于这个大小的模块不会被分割
      // minRemainingSize: 0, // 类似于minSize，最后确保提取的文件大小不能为0
      // minChunks: 1, //  模块被引用的最小次数，低于这个次数的模块不会被分割。
      // maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量，超过30个共同引用，不做拆分（import过多会影响性能）
      // maxInitialRequests: 30, // 入口js文件最大并行请求数量
      // enforceSizeThreshold: 50000, // 超过50kb一定会单独打包（此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests）
      
      // 缓存组配置，允许你定义特定的分割规则
      // cacheGroups: { // 组，哪些模块要打包到一个组
      //   defaultVendors: { // 组名
      //     test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块，这些会打包进defaultVendors中
      //     priority: -10, // 优先级，权重（越大越高）
      //     reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块，则它将被重用，而不是生成新的模块
      //   },
      //   default: { // 其他没有写的配置会使用上面的默认值，写了的会覆盖上面的配置
      //     minChunks: 2, // ，至少被用2次，才被拆分，这里的minChunks权重更大，会覆盖掉上面的minChunks: 1
      //     priority: -20,
      //     reuseExistingChunk: true,
      //   },
      // },
      // 修改配置
      cacheGroups: {
        // 组，哪些模块要打包到一个组
        // defaultVendors: { // 组名
        //   test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
        //   priority: -10, // 权重（越大越高）
        //   reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块，则它将被重用，而不是生成新的模块
        // },
        default: {
          // 其他没有写的配置会使用上面的默认值
          minSize: 0, // 我们定义的文件体积太小了，所以要改打包的最小文件体积，测试后文件没20kb，所有设置0，方便测试
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
  // 模式
  mode: "production",
  devtool: "source-map"
}
